package seedbed_allocation_batch_record

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"math"
	"strconv"
	"strings"
	"time"

	"github.com/jinzhu/gorm"

	"github.com/gin-gonic/gin"

	rich_err "app/error"
	"app/models"
	"app/service"
	"app/service/greenhouse_allocation_record"
	"app/service/orders"
)

func Gets(context *gin.Context) ([]*models.SeedbedAllocationBatchRecordDetail, *models.Pager, *rich_err.RichError) {
	base := models.Orm.Model(&models.SeedbedAllocationBatchRecord{}).
		Select("seedbed_allocation_batch_record.*, orders.name as orders_name,  greenhouse.name as greenhouse_name").
		Joins("LEFT JOIN orders ON seedbed_allocation_batch_record.order_id = orders.id").
		Joins("LEFT JOIN greenhouse ON seedbed_allocation_batch_record.greenhouse_id = greenhouse.id")

	results, pager, err := service.GetDetails[models.SeedbedAllocationBatchRecordDetail](context, base, models.SeedbedAllocationBatchRecord{}.TableName(), map[string]string{"orders_name": "orders.name", "greenhouse_name": "greenhouse.name"})

	if err != nil {
		return nil, nil, rich_err.NewError(rich_err.RequestInvalid, err)
	}

	// 批量查询seedbed记录
	seedbedIds := make([]string, 0)
	for _, record := range results {
		seedbedIds = append(seedbedIds, strings.Split(record.SeedbedIDs, ",")...)
	}
	seedbeds := make([]*models.Seedbed, 0)
	err = models.Orm.Model(models.Seedbed{}).Where("id IN (?)", seedbedIds).Find(&seedbeds).Error
	if err != nil {
		return nil, nil, rich_err.NewError(rich_err.DatabaseFailed, err)
	}

	// 整理好赋值给SeedbedAllocationBatchRecordDetail的Seedbeds
	for _, record := range results {
		detailSeedbeds := make([]*models.Seedbed, 0)
		seedbedIds := strings.Split(record.SeedbedIDs, ",")
		for _, seedbed := range seedbeds {
			if contains(seedbedIds, strconv.Itoa(seedbed.ID)) {
				detailSeedbeds = append(detailSeedbeds, seedbed)
			}
		}
		record.Seedbeds = detailSeedbeds
	}

	return results, pager, nil
}

func Get(id string) (*models.SeedbedAllocationBatchRecordDetail, *rich_err.RichError) {
	base := models.Orm.Model(&models.SeedbedAllocationBatchRecord{}).
		Select("seedbed_allocation_batch_record.*, orders.name as orders_name,  greenhouse.name as greenhouse_name").
		Joins("LEFT JOIN orders ON seedbed_allocation_batch_record.order_id = orders.id").
		Joins("LEFT JOIN greenhouse ON seedbed_allocation_batch_record.greenhouse_id = greenhouse.id")

	result, err := service.GetDetail[models.SeedbedAllocationBatchRecordDetail](id, base)

	if err != nil {
		return nil, rich_err.NewError(rich_err.RequestInvalid, err)
	}

	// 读取seedbed_ids的值
	seedbedIds := strings.Split(result.SeedbedIDs, ",")

	seedbeds := make([]*models.Seedbed, 0)
	err = models.Orm.Model(models.Seedbed{}).Where("id IN (?)", seedbedIds).Find(&seedbeds).Error
	if err != nil {
		if err != nil {
			return nil, rich_err.NewError(rich_err.DatabaseFailed, err)
		}
	}

	// 整理好赋值给SeedbedAllocationBatchRecordDetail的Seedbeds
	result.Seedbeds = seedbeds

	if err != nil {
		return nil, rich_err.NewError(rich_err.RequestInvalid, err)
	}
	return result, nil
}

func Create(context *gin.Context) (*models.SeedbedAllocationBatchRecordDetail, *rich_err.RichError) {
	bodyBytes, err := ioutil.ReadAll(context.Request.Body)
	if err != nil {
		return nil, rich_err.NewError(rich_err.RequestInvalid, err)
	}
	// 重新写入原始数据到 context.Request.Body 中
	context.Request.Body = io.NopCloser(bytes.NewReader(bodyBytes))

	req := new(models.SeedbedAllocationBatchRecordCore)
	err = json.Unmarshal(bodyBytes, req)
	if err != nil {
		return nil, rich_err.NewError(rich_err.RequestInvalid, err)
	}

	// 判断唯一索引是否存在,存在的话,直接换成update
	var exited models.SeedbedAllocationBatchRecord
	models.Orm.Table("seedbed_allocation_batch_record").Select("id").Where("greenhouse_id = ? and greenhouse_allocation_id = ? and seedbed_ids = ?", req.GreenhouseID, req.GreenhouseAllocationID, req.SeedbedIDs).First(&exited)

	if exited.ID > 0 {
		dateTimeNow := time.Now().Format("2006-01-02 15:04:05")
		remark := exited.Remark + "; " + dateTimeNow + " 新增: " + strconv.Itoa(req.Quantity)
		context.AddParam("id", strconv.Itoa(exited.ID))
		return Update(context, remark)
	}

	data := models.SeedbedAllocationBatchRecord{SeedbedAllocationBatchRecordCore: *req}
	if data.Quantity == 0 {
		data.Quantity = data.TrayNumber * data.UnitNumber
	}
	result := models.Orm.Create(&data)
	if result.Error != nil {
		return nil, rich_err.NewError(rich_err.DatabaseFailed, result.Error)
	}
	err = orders.UpdateAllocatedSeedbedQuantity(req.OrderID)
	if err != nil {
		return nil, rich_err.NewError(rich_err.DatabaseFailed, err)
	}
	err = greenhouse_allocation_record.UpdateAllocatedSeedbedQuantity(data.GreenhouseAllocationID)
	if err != nil {
		return nil, rich_err.NewError(rich_err.DatabaseFailed, err)
	}
	// 更新订单成已分苗床
	if err := models.Orm.Model(&models.Orders{}).Where("id = ?", req.OrderID).Update("order_status", 7).Error; err != nil {
		return nil, rich_err.NewError(rich_err.DatabaseFailed, err)
	}
	return Get(strconv.Itoa(data.ID))
}

func Update(context *gin.Context, remark string) (*models.SeedbedAllocationBatchRecordDetail, *rich_err.RichError) {
	req := new(models.SeedbedAllocationBatchRecordDelta)
	if err := context.ShouldBindJSON(req); err != nil {
		return nil, rich_err.NewError(rich_err.RequestInvalid, err)
	}

	data, err := service.Get[models.SeedbedAllocationBatchRecord](context)
	if err != nil {
		return nil, rich_err.NewError(rich_err.RequestInvalid, err)
	}
	if req.TrayNumber != nil {
		data.TrayNumber = int(math.Round(req.TrayNumber.(float64)))
	}
	if req.UnitNumber != nil {
		data.UnitNumber = int(math.Round(req.UnitNumber.(float64)))
	}
	if req.Quantity != nil {
		data.Quantity = int(math.Round(req.Quantity.(float64)))
	} else {
		data.Quantity = data.TrayNumber * data.UnitNumber
	}
	if req.GreenhouseID != nil {
		data.GreenhouseID = int(math.Round(req.GreenhouseID.(float64)))
	}
	if req.SeedbedIDs != nil {
		data.SeedbedIDs = req.SeedbedIDs.(string)
	}
	if req.GreenhouseAllocationID != nil {
		data.GreenhouseAllocationID = int(math.Round(req.GreenhouseAllocationID.(float64)))
	}
	if req.OrderID != nil {
		data.OrderID = int(math.Round(req.OrderID.(float64)))
	}
	if req.Remark != nil {
		data.Remark = req.Remark.(string)
	}
	if remark != "" {
		data.Remark = remark
	}
	result := models.Orm.Save(data)
	if result.Error != nil {
		return nil, rich_err.NewError(rich_err.DatabaseFailed, result.Error)
	}
	err = orders.UpdateAllocatedSeedbedQuantity(data.OrderID)
	if err != nil {
		return nil, rich_err.NewError(rich_err.DatabaseFailed, err)
	}
	err = greenhouse_allocation_record.UpdateAllocatedSeedbedQuantity(data.GreenhouseAllocationID)
	if err != nil {
		return nil, rich_err.NewError(rich_err.DatabaseFailed, err)
	}
	return Get(strconv.Itoa(data.ID))
}

func Delete(context *gin.Context) *rich_err.RichError {
	data, err := service.Get[models.SeedbedAllocationBatchRecord](context)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil
		}
		return rich_err.NewError(rich_err.RequestInvalid, err)
	}
	result := models.Orm.Delete(data)
	if result.Error != nil {
		return rich_err.NewError(rich_err.DatabaseFailed, result.Error)
	}
	err = orders.UpdateAllocatedSeedbedQuantity(data.OrderID)
	if err != nil {
		return rich_err.NewError(rich_err.DatabaseFailed, err)
	}
	err = greenhouse_allocation_record.UpdateAllocatedSeedbedQuantity(data.GreenhouseAllocationID)
	if err != nil {
		return rich_err.NewError(rich_err.DatabaseFailed, err)
	}
	return nil
}

func contains(arr []string, str string) bool {
	for _, a := range arr {
		if a == str {
			return true
		}
	}
	return false
}
